package com.controller;

import java.awt.Component;
import java.awt.Dimension;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JPanel;

import com.animation.PlaneRunnable;
import com.dequeue.DeQueueList;
import com.domain.Aeropuerto;
import com.domain.Avion;
import com.domain.EmptyParkException;
import com.domain.threads.EjecutorHiloUnicoInterfazGrafica;
import com.queue.PriorityQueueList;
import com.stack.StackList;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.view.MainWindow;
import com.view.utils.PlaneButton;

//este comentario es para probar el push
public class MainWindowController {

	private static Logger LOGGER = Logger.getLogger(MainWindowController.class
			.getName());

	// Servicio que lanza 1...* ejecutables en distintos hilos de ejecucion
	// simultaneamente.
	private static ExecutorService backgroundExec;

	private static MainWindowController instancia = null;
	private static Aeropuerto MeridaAirport;
	private static DeQueueList parkingLane;
	private static StackList stackAviones;
	private static PriorityQueueList enEspera;

	private static XStream xstream;

	// Se asignan los atributos estaticamente
	static {
		backgroundExec = Executors.newCachedThreadPool();
		xstream = new XStream(new DomDriver());
		LOGGER.setLevel(Level.INFO);
	}

	public static final MainWindowController getInstance() {
		if (instancia == null) {
			instancia = new MainWindowController();
		}
		return instancia;
	}

	private MainWindowController() {
		// TODO Auto-generated constructor stub
		MeridaAirport = new Aeropuerto();
		xstream.alias("estacionamiento", DeQueueList.class);
		randomizeInit();
		initAirport();
	}

	private static void randomizeInit() {

		// MeridaAirport.generacionAleatoria();

		MeridaAirport.llegada(new Avion("A", 2132, 32));
		MeridaAirport.llegada(new Avion("B", 2132, 32));
		MeridaAirport.llegada(new Avion("C", 2132, 32));
		MeridaAirport.llegada(new Avion("D", 2132, 32));
		MeridaAirport.llegada(new Avion("E", 2132, 32));
		MeridaAirport.llegada(new Avion("F", 2132, 32));
		MeridaAirport.llegada(new Avion("G", 2132, 32));
		MeridaAirport.llegada(new Avion("H", 2132, 32));
		MeridaAirport.llegada(new Avion("I", 2132, 32));
		MeridaAirport.llegada(new Avion("J", 2132, 32));
		MeridaAirport.llegada(new Avion("K", 2132, 32));
		MeridaAirport.llegada(new Avion("L", 2132, 32));
		MeridaAirport.llegada(new Avion("M", 2132, 32));
		MeridaAirport.llegada(new Avion("N", 2132, 32));
		MeridaAirport.llegada(new Avion("O", 2132, 32));
		MeridaAirport.llegada(new Avion("P", 2132, 32));

	}

	public static void initAirport() {

		MainWindow.getInstance();
		populateTaxiLane();
		populateHoldingPattern();
		/*
		 * // Agregamos las avionetas // aeropuerto.llegada(uno);
		 * aeropuerto.llegada(dos); aeropuerto.llegada(tres);
		 * aeropuerto.llegada(cuatro); aeropuerto.llegada(cinco);
		 * aeropuerto.llegada(seis); aeropuerto.llegada(siete);
		 * aeropuerto.llegada(ocho); aeropuerto.llegada(nueve);
		 * aeropuerto.llegada(diez); aeropuerto.llegada(once);
		 * aeropuerto.llegada(doce); aeropuerto.llegada(trece);
		 * aeropuerto.llegada(catorce); aeropuerto.llegada(quince);
		 * aeropuerto.llegada(diezyseis);
		 */

	}

	public static void populateTaxiLane() {

		// Crea un XML del estacionamiento del Aeropuerto, y el estacionamiento
		// grafico lo instancia.
		parkingLane = (DeQueueList) xstream.fromXML(xstream.toXML(MeridaAirport
				.getEstacionamiento()));

		// Instancia la ventana, y elimina todos los aviones de la pista
		// TaxiLane
		MainWindow ventana = MainWindow.getInstance();
		ventana.wipeTaxiLane();

		Avion avionEnPista;

		while (!parkingLane.isEmpty()) {
			avionEnPista = (Avion) MainWindowController.parkingLane
					.removeFromLast();
			ventana.drawTaxiLane(avionEnPista.getNumMatricula(),
					avionEnPista.getNumPasajeros(),
					avionEnPista.getCantidadFuel());
		}

	}

	public static void populateHoldingPattern() {

		enEspera = (PriorityQueueList) xstream.fromXML(xstream
				.toXML(MeridaAirport.getEnEspera()));

		MainWindow ventana = MainWindow.getInstance();
		ventana.wipeHoldingPattern();

		Avion avionEnPista;

		while (!enEspera.isEmpty()) {
			avionEnPista = (Avion) MainWindowController.enEspera
					.removeMinElement();
			ventana.drawSky(avionEnPista.getNumMatricula(),
					avionEnPista.getNumPasajeros(),
					avionEnPista.getCantidadFuel());
		}

	}

	public static void arrive(final String matricula, final int pasajeros,
			final int fuel) {

		final MainWindow ventana = MainWindow.getInstance();

		setAllButtonsEnableTo(false);

		// El Servicio ejecutor lanza un nuevo ejecutable...
		backgroundExec.execute(new Runnable() {
			@Override
			public void run() {
				try {

					Avion avionLlegando = new Avion(matricula, pasajeros, fuel);

					boolean pistaLlena = MeridaAirport.llegada(avionLlegando);

					// Pista Taxi llena
					if (pistaLlena) {
						populateHoldingPattern();
					} else {// Pista Vacia
						landing(avionLlegando);
						populateTaxiLane();
					}

				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					System.out.println("Algo salio mal en el thread)");
				} finally {
					// El hilo ejecutor Swing lanza el siguiente ejecutable...
					EjecutorHiloUnicoInterfazGrafica.instance().execute(
							new Runnable() {
								@Override
								public void run() {
									setAllButtonsEnableTo(true);
								}
							});
				}
			}
		});

	}

	private static void landing(Avion avionLlegando)
			throws InterruptedException {

		final MainWindow ventana = MainWindow.getInstance();
		ventana.getLandingPanel().animate();

	}

	public static void departure() {

		final MainWindow ventana = MainWindow.getInstance();

		setAllButtonsEnableTo(false);

		// El Servicio ejecutor lanza un nuevo ejecutable...
		backgroundExec.execute(new Runnable() {
			@Override
			public void run() {
				try {

					Avion avionDespegando = MeridaAirport.salida();

					if (avionDespegando != null) {

						populateTaxiLane();
						populateHoldingPattern();

						// Pista Despegue

						JPanel runway = ventana.getRunwayPanel();

						ventana.drawPlaneToRunway(
								avionDespegando.getNumMatricula(),
								avionDespegando.getNumPasajeros(),
								avionDespegando.getCantidadFuel());

						(new PlaneRunnable((ImageIcon) ((PlaneButton) runway
								.getComponent(0)).getIcon(),
								(PlaneButton) runway.getComponent(0), runway))
								.takeOff();

						Thread.sleep(1400);
						
					}

				} catch (EmptyParkException e) {

					// El hilo ejecutor Swing lanza el siguiente ejecutable...
					EjecutorHiloUnicoInterfazGrafica.instance().execute(
							new Runnable() {
								@Override
								public void run() {
									ventana.setTitle("Joeer");
								}
							});

				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					System.out.println("Algo salio mal en el thread)");
				} finally {
					// El hilo ejecutor Swing lanza el siguiente ejecutable...
					EjecutorHiloUnicoInterfazGrafica.instance().execute(
							new Runnable() {
								@Override
								public void run() {
									setAllButtonsEnableTo(true);
								}
							});
				}
			}
		});

	}

	public static void retirePlane(final String matricula) {

		setAllButtonsEnableTo(false);
		
		// El Servicio ejecutor lanza un nuevo ejecutable...
		backgroundExec.execute(new Runnable() {
			@Override
			public void run() {
				try {

					stackAviones = MeridaAirport.getPila();
					parkingLane = MeridaAirport.getEstacionamiento();

					MainWindow ventana = MainWindow.getInstance();

					if (((Avion) parkingLane.last()).getNumMatricula().equals(
							matricula)) {

						LOGGER.info(((Avion)parkingLane.removeFromLast()).toDataString());
						populateTaxiLane();

					} else {

						// Configuracion del panel en donde se va a dibujar los
						// aviones puestos
						// en el Stack
						Dimension tamanio = ventana.getStackLayer().getSize();
						/*
						 * int x = (tamanio.width / 2) - 30; int y =
						 * tamanio.height - 50;
						 * 
						 * int offset = 41;
						 */

						int x = (tamanio.width / 2) - 35;
						int y = tamanio.height - 71;
						int offset = 46;

						System.out.println(tamanio.getSize());

						int contadorComponentes = 0;

						while (!parkingLane.isEmpty()
								&& !((Avion) parkingLane.last())
										.getNumMatricula().equals(matricula)) {

							Thread.sleep(1000);

							// Operaciones de datos
							Avion avionSacadodeParque = (Avion) parkingLane
									.removeFromLast();
							stackAviones.push(avionSacadodeParque);

							// Operaciones Swing
							ventana.removeLastTaxiLanePlane();

							JButton avion = new PlaneButton(avionSacadodeParque
									.getNumMatricula(), avionSacadodeParque
									.getNumPasajeros(), avionSacadodeParque
									.getCantidadFuel(),
									PlaneButton.STACK_PLANE, false);

							avion.setBounds(x, y, 60, 60);

							y -= offset;

							ventana.getStackLayer().add(avion,
									new Integer(contadorComponentes++), 0);

						}

						// Se retira el avion coincidente
						//AQUI VA EL LOGGER
						Avion avionAveriado = (Avion) parkingLane
								.removeFromLast();
						LOGGER.info(avionAveriado.toDataString());
						
						ventana.drawRetiredPlane(
								avionAveriado.getNumMatricula(),
								avionAveriado.getNumPasajeros(),
								avionAveriado.getCantidadFuel());
						ventana.removeLastTaxiLanePlane();

						while (!stackAviones.isEmpty()) {

							Thread.sleep(1000);

							// Operaciones de datos
							Avion avionSacadodeStack = (Avion) stackAviones
									.pop();
							parkingLane.insertLast(avionSacadodeStack);

							// Operaciones Swing
							ventana.getStackLayer().remove(0);
							ventana.getStackLayer().repaint();
							ventana.drawFirstPlaneTaxi(
									avionSacadodeStack.getNumMatricula(),
									avionSacadodeStack.getNumPasajeros(),
									avionSacadodeStack.getCantidadFuel());
						}
					}

				} catch (EmptyParkException e) {

					// El hilo ejecutor Swing lanza el siguiente ejecutable...
					EjecutorHiloUnicoInterfazGrafica.instance().execute(
							new Runnable() {
								@Override
								public void run() {

								}
							});

				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					System.out.println("Algo salio mal en el thread)");
				} finally {
					// El hilo ejecutor Swing lanza el siguiente ejecutable...
					EjecutorHiloUnicoInterfazGrafica.instance().execute(
							new Runnable() {
								@Override
								public void run() {
									System.out.append(null);
									setAllButtonsEnableTo(true);

								}
							});
				}
			}
		});

	}

	private static void setAllButtonsEnableTo(boolean state) {

		Component[] com = MainWindow.getInstance().getControlPanel()
				.getComponents();
		// Activando/Desactivando todos los botones del Control Panel
		for (int a = 0; a < com.length; a++) {
			com[a].setEnabled(state);
		}

		com = MainWindow.getInstance().getTaxiLanePanel().getComponents();
		for (int a = 0; a < com.length; a++) {
			com[a].setFocusable(state);
		}
	}

}
